package com.spring;

import com.example.thinvent.UserService;
import org.springframework.beans.factory.BeanFactory;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ApplicationContext {

    private Map<String, BeanDefinition> beanDefinitions = new HashMap<>();
    private Map<String, Object> singletonObjects = new HashMap<>();


    public ApplicationContext(Class configClass) {
        //扫描类，获取BeanDefinition
        scan(configClass);

        //初始化非懒加载的单例Bean,懒加载不做实现
        instanceSingletonBean();

    }

    private void instanceSingletonBean() {
        for (String beanName : beanDefinitions.keySet()) {
            BeanDefinition beanDefinition = beanDefinitions.get(beanName);
            if (beanDefinition.getScope().equals(ScopeEnum.singleton)) {
                if (!singletonObjects.containsKey(beanName)) {
                    Object bean = doCreatBean(beanDefinition);
                    singletonObjects.put(beanDefinition.getBeanName(), bean);
                }
            }
        }
    }

    private Object doCreatBean(BeanDefinition beanDefinition) {
        Class beanClass = beanDefinition.getType();
        try {
            Constructor declaredConstructor = beanClass.getConstructor();
            Object instance = declaredConstructor.newInstance();

            //注入参数
            Field[] fields = beanClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    field.set(instance,getBean(fieldName));
                }
            }

            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }


        return null;
    }

    private void scan(Class configClass) {
        ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        String packagePath = componentScanAnnotation.value();
        //获取包下的所有class集合
        List<Class> beanClasses = getBeanClasses(packagePath);
        for (Class beanClass : beanClasses) {
            if (beanClass.isAnnotationPresent(Component.class)) {
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setType(beanClass);
                Component component = (Component) beanClass.getAnnotation(Component.class);
                String beanName = component.value();
                if ("".equals(beanName)) {
                    beanName = Introspector.decapitalize(beanClass.getSimpleName());
                }
                beanDefinition.setBeanName(beanName);
                if (beanClass.isAnnotationPresent(Scope.class)) {
                    Scope scope = (Scope) beanClass.getAnnotation(Scope.class);
                    beanDefinition.setScope(scope.value());
                } else {
                    beanDefinition.setScope(ScopeEnum.singleton);
                }
                beanDefinitions.put(beanName, beanDefinition);
            }

        }
    }

    private List<Class> getBeanClasses(String packagePath) {
        List<Class> beanClasses = new ArrayList<>();
        ClassLoader classLoader = ApplicationContext.class.getClassLoader();
        packagePath = packagePath.replace(".", "/");
        URL resource = classLoader.getResource(packagePath);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                String fileName = f.getAbsolutePath();
                if (fileName.endsWith(".class")) {
                    String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                    className = className.replace("\\", ".");
                    try {
                        Class<?> clazz = classLoader.loadClass(className);
                        beanClasses.add(clazz);
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
        return beanClasses;
    }

    public Object getBean(String beanName) {

        if (!beanDefinitions.containsKey(beanName)) {
            throw new NullPointerException();
        }

        BeanDefinition beanDefinition = beanDefinitions.get(beanName);
        //从bean容器中获取bean
        if (beanDefinition.getScope().equals(ScopeEnum.singleton)) {
            Object singletonBean = singletonObjects.get(beanName);
            if (singletonBean == null) {
                singletonBean = doCreatBean(beanDefinition);
                singletonObjects.put(beanName, singletonBean);
            }
            return singletonBean;
        }else{
            Object prototypeBean = doCreatBean(beanDefinition);
            return prototypeBean;
        }

    }
}
